/**
 * 
 */
package com.cmpanyandi.elearning.utils.db;

import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
import com.cmpanyandi.elearning.utils.db.DBDescriptor.UpdateStatemet;

/**
 * This adapter is responsible for providing DAO to SQL lite.
 * 
 * @author wojtek
 * 
 */
public class DbAdapter {

    private Context context;
    private DBDescriptor descriptor;
    private DatabaseHelper mDbHelper;
    private SQLiteDatabase mDb;

    private static DbAdapter instance = null;

    /**
     * This method initialise context of
     * 
     * @param context
     * @param descriptor
     */
    public static void init(Context context, DBDescriptor descriptor) {
	
	if (instance == null) {
	    instance = new DbAdapter(context, descriptor);
	    instance.open();
	    Log.w(TAG, "Database has been initilised");
	}
    }

    /**
     * Return single instance of object.
     * 
     * @return
     */
    public static DbAdapter getInstance() {

	return instance;
    }

    private void validate() {
	if (context == null) {
	    throw new RuntimeException("Context in not initialize");
	}

	if (descriptor == null) {
	    throw new RuntimeException("Descriptor in not initialize");
	}
    }

    /**
     * Constructor - takes the context to allow the database to be
     * opened/created
     * 
     * @param ctx
     *            the Context within which to work
     */
    public DbAdapter(Context ctx, DBDescriptor dbDescriptor) {
	this.context = ctx;
	this.descriptor = dbDescriptor;
    }

    private DbAdapter() {
	// TODO Auto-generated constructor stub
    }

    /**
     * This method open database connection in writable mode.
     * 
     * @return DBAdapter
     * @throws SQLException
     */
    public DbAdapter open() throws SQLException {
	mDbHelper = new DatabaseHelper(context, descriptor);
	mDb = mDbHelper.getWritableDatabase();
	return this;
    }

    /**
     * Close database.
     */
    public void close() {
	mDbHelper.close();
    }

    private static class DatabaseHelper extends SQLiteOpenHelper {
	private DBDescriptor dbDescriptor;

	DatabaseHelper(Context context, DBDescriptor dbDescriptor) {
	    super(context, dbDescriptor.getDatabaseName(), null, dbDescriptor.getVersion());
	    this.dbDescriptor = dbDescriptor;
	}

	@Override
	public void onCreate(SQLiteDatabase db) {
	    for (String stmt : dbDescriptor.getCreateStatements()) {
		db.execSQL(stmt);
		Log.w(TAG, "invocation of creation stmt" + stmt);
	    }
	}

	/**
	 * Upgrade DB schema.
	 */
	@Override
	public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
	    Log.w(TAG, "Upgrading database from version " + oldVersion + " to " + newVersion
		    + ", which will destroy all old data");

	    if (oldVersion != newVersion) {

		for (UpdateStatemet updateStmt : dbDescriptor.getUpdateStatements()) {

		    if (updateStmt.getVersion() > oldVersion) {
			db.execSQL(updateStmt.getStatement());
			Log.w(TAG, "invocation of creation stmt" + updateStmt.getVersion() + ": "
				+ updateStmt.getStatement());
		    }
		}

	    }
	}
    }

    /**
     * Persist bean in database.
     * 
     * @param bean
     *            - bean name.
     */
    public void saveOrUpdate(DBBean bean) {

	if (bean.isInsertRequired()) {
	    bean.setPk(mDb.insert(bean.getTableName(), null, bean.getContentValues()));
	} else {
	    mDb.update(bean.getTableName(), bean.getContentValues(), bean.getIdentityWhereClause(), null);
	}
    }

    /**
     * Return instance of bean by provided getPK() from bean
     * 
     * @param bean
     *            - bean with set pk.
     * @return
     * @return - return instance of bean.
     * @throws SQLException
     */
    public <T extends DBBean> DBBean getByPK(DBBean bean) throws SQLException {

	Cursor mCursor =

	mDb.query(true, bean.getTableName(), bean.getSelectionColumns(), bean.getIdentityWhereClause(), null, null,
		null, null, null);

	if (mCursor != null) {
	    mCursor.moveToFirst();
	}

	bean.initFromCursor(mCursor);
	return bean;

    }

    /**
     * This method is responsible for deleting a bean.
     * 
     * @param bean
     *            - bean name.
     */
    public void delete(DBBean bean) {

	mDb.delete(bean.getTableName(), bean.getIdentityWhereClause(), null);
    }

    /**
     * Return a Cursor over the list of all DBBean in the database
     * 
     * @return Cursor over all dbbeans from which had been persisted.
     */
    public Cursor fetchBeans(DBBean bean) {
	return mDb.query(bean.getTableName(), bean.getSelectionColumns(), bean.getWherePrepareStmtClause(), bean
		.getWherePrepareStmtArgs(), null, null, null, null);

    }

    /**
     * This method construct query from {@link QueryBuilder}
     * 
     * @param builder
     *            @link {@link QueryBuilder}
     * @return @link {@link Cursor}
     */
    public Cursor invokeQuery(QueryBuilder builder) {
	return mDb.rawQuery(builder.getQueryString(), builder.getBindingsValues());
    }

    private static final String TAG = "DbAdapter";

}
